package org.hcf.common.util;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

public class HexUtils {
    public static byte[] nums = new byte[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
    public static char[] lowers = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    public static char[] uppers = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    public static byte[] toBytes(String hex) {
        if (hex == null) return null;
        if ((hex.length() & 1) != 0) hex = '0' + hex;
        char[] chars = hex.toCharArray();
        byte[] bytes = new byte[chars.length / 2];
        for (int i = 0, j = 0; i < chars.length; i += 2) {
            bytes[j++] = (byte) ((nums[chars[i]] << 4) | nums[chars[i + 1]]);
        }
        return bytes;
    }

    public static String toHex(byte[] bs) {
        return toHex(bs, true);
    }

    public static String toHex(byte[] bs, boolean isUpper) {
        return toHex(bs, isUpper ? uppers : lowers);
    }

    public static String toHex(byte[] bs, char[] chars) {
        int len = bs.length;
        char[] cs = new char[len << 1];
        for (int index = 0, i = 0; i < len; i++) {
            cs[index++] = chars[(bs[i] & 240) >> 4];
            cs[index++] = chars[bs[i] & 15];
        }
        return new String(cs);
    }

    public static byte[] getSKey(byte[] bs) {
        byte[] keys = new byte[bs.length > 64 ? 64 : (bs.length % 16 == 0 ? bs.length : (bs.length / 16 + 1) * 16)];
        copy(bs, keys);
        return keys;
    }

    public static byte[] getIV(byte[] bs) {
        byte[] iv = new byte[16];
        copy(bs, iv);
        return iv;
    }

    public static void copy(byte[] src, byte[] tgt) {
        for (int i = 0; i < src.length && i < tgt.length; i++) {
            tgt[i] = src[i];
        }
    }


    public static byte[] getHexNumBytes() {
        if (nums == null) {
            nums = new byte[128];
            for (int i = 0; i < 128; i++) {
                if (i >= 48 && i < 58) {
                    nums[i] = (byte) (i - 48);
                } else if (i >= 65 && i < 71) {
                    nums[i] = (byte) (i - 55);
                } else if (i >= 97 && i < 103) {
                    nums[i] = (byte) (i - 87);
                } else nums[i] = (byte) (-1);

            }

        }
        return nums;
    }

    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 128; i++) {
            if (i >= 48 && i < 58) {
                sb.append((i - 48) + ",");
            } else if (i >= 65 && i < 71) {
                sb.append((i - 55) + ",");
            } else if (i >= 97 && i < 103) {
                sb.append((i - 87) + ",");
            } else sb.append(-1 + ",");
        }
        System.out.println(sb);


        String data = "abcdefabcdeffffdddaaacccbacabc1112244435342312123423";
        byte[] bs = new BigInteger(data, 16).toByteArray();
        byte[] bs1 = toBytes(data);
        byte[] bs2 = HexUtil.decodeHex(data);

        String data1 = new BigInteger(1, bs).toString(16);
        String data2 = toHex(bs1);
        char[] data3 = HexUtil.encodeHex(bs2);
        System.out.println(getByteString(bs));
        System.out.println(getByteString(bs1));
        System.out.println(getByteString(bs2));
        System.out.println(data);
        System.out.println(data1);
        System.out.println(data2.toLowerCase());
        System.out.println(data3);
        int len = 1000000;
        List<String> list = new ArrayList<>(len);
        for (int i = 0; i < len; i++) {
            list.add(randomString());
            if (list.size() % 100000 == 0) System.out.println(list.size());
        }
        List<byte[]> bss = new ArrayList<>(len);
        for (String str : list) {
            byte[] temp = toBytes(str);
            bss.add(temp);
//            toHex(temp);
        }

        long sta = System.currentTimeMillis();
        for (String str : list) {
            equals(str);
        }
        System.out.println("当前类比较[" + len + "]次16进制编、解码比较用时:" + (double) (System.currentTimeMillis() - sta) / 1000 + "\n\n\n");


//        List<byte[]> bss2 = new ArrayList<>(len);
        sta = System.currentTimeMillis();
        for (String str : list) {
            byte[] temp = toBytes(str);
//            bss.add(temp);
//            toHex(temp);
        }
        System.out.println("当前类[" + len + "]次编码16进制用时:" + (double) (System.currentTimeMillis() - sta) / 1000);

        sta = System.currentTimeMillis();
        for (String str : list) {
            byte[] temp = HexUtil.decodeHex(str);
//            bss2.add(temp);
//            HexUtil.encodeHexStr(temp);
        }
        System.out.println("HexUtil[" + len + "]次编码16进制用时:" + (double) (System.currentTimeMillis() - sta) / 1000);
        for (byte[] bytes : bss) {
            String temp = toHex(bytes);
        }
        sta = System.currentTimeMillis();
        for (byte[] bytes : bss) {
            String temp = HexUtil.encodeHexStr(bytes);
        }
        System.out.println("HexUtil[" + len + "]次解码16进制用时:" + (double) (System.currentTimeMillis() - sta) / 1000);
        sta = System.currentTimeMillis();
        for (byte[] bytes : bss) {
            String temp = toHex(bytes);
        }
        System.out.println("当前类[" + len + "]次解码16进制用时:" + (double) (System.currentTimeMillis() - sta) / 1000);
    }

    static void equals() {
        String data = randomString();
        equals(data);
    }

    static void equals(String data) {
        byte[] bs1 = HexUtil.decodeHex(data);
        byte[] bs2 = toBytes(data);
        if (!equals(bs1, bs2)) {
            System.err.println("由数据[" + data + "]生成两个不相同的数据流" + getByteString(bs1) + getByteString(bs2));
            return;
        }
        String data1 = HexUtil.encodeHexStr(bs1);
        String data2 = toHex(bs2);
        if (!StrUtil.equals(data1, data2.toLowerCase())) {
            System.err.println("由数据[" + data + "]生成两个不相同的数据[" + data1 + "][" + data2 + "]" + getByteString(bs1) + getByteString(bs2));
        }

    }

    static boolean equals(byte[] bs1, byte[] bs2) {
        if (bs1 == null || bs2 == null || bs1.length != bs2.length) return false;
        for (int i = 0; i < bs1.length; i++) if (bs1[i] != bs2[i]) return false;
        return true;
    }

    static String randomString() {
        int len = 100;// RandomUtils.nextInt(8, 50) * 2;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < len; i++) {
            sb.append(lowers[RandomUtil.randomInt(0, lowers.length)]);
        }
        return sb.toString();
    }

    static String getByteString(byte[] bs) {
        int[] arr = new int[bs.length];
        for (int i = 0; i < bs.length; i++) {
            arr[i] = bs[i];
        }
        return JSONObject.toJSONString(arr);
    }
}
